function AjaxObject() {
    this.readyState = 0;
    this.responseText = '';
    this._createAjaxObject();
}
AjaxObject.prototype = {
    GET: 'GET',
    POST: 'POST',

// Public methods
    open: function(method, url) {
        if (!this.ajax) {
            return;
        }
        this.ajax.open(method, url, true);
        if (method == this.POST) {
            this.ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            this.ajax.setRequestHeader('Connection', 'close');
        }
    },
    send: function(body) {
        if (!this.ajax) {
            return;
        }
        try {
            this.ajax.send(body);
        } catch(e) {
        }
    },
    abort: function() {
        if (!this.ajax) {
            return;
        }
        this.ajax.abort();
    },
    onreadystatechange: function() {
        return true
    },

// Private methods
    _onreadystatechange: function() {
        this.readyState = this.ajax.readyState;
        if (this.readyState == 4) {
            this.contentType = this.ajax.getResponseHeader("Content-Type");
            this.responseText = this.ajax.responseText;
            if (typeof(this.onreadycontent) == 'function' && this.ajax.status == 200) {
                return this.onreadycontent();
            } else if (typeof(this.onerrorstate) == 'function' && this.ajax.status != 200) {
                return this.onerrorstate();
            }
        }
        try {
            if (typeof(this.onreadystatechange) == 'function' && this.ajax.status == 200) {
                return this.onreadystatechange();
            }
        } catch(e) {
        }
        return false;
    },
    _createAjaxObject: function() {
        this.ajax = this._getAjaxObject();
        if (!this.ajax) {
            return null;
        }
        var _this = this;
        this.ajax.onreadystatechange = function() {
            _this._onreadystatechange();
        }
        return true;
    },
    _getAjaxObject: function() {
        try {
            return new XMLHttpRequest();
        } catch(e) {
            var objects = ['MSXML2.XMLHTTP.5.0','MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'];
            for (var i = 0; i < objects.length; i++) {
                try {
                    return new ActiveXObject(objects[i]);
                } catch(e) { }
            }
            return false;
        }
    }
}


// AJAXRequest -- функция-обертка для AjaxObject 
// создает новый AjaxObject, отправляет запрос, принимает ответ и вызывает нужные функции 
// Параметры: 
// method -- 'GET' или 'POST'
// paramstr -- параметры запроса; строчка или ассоциированный массив 
//     пример: "cmd=ajaxGetSmth&easy=yes&detail=no" или {"cmd": "ajaxGetSmth", "easy": "yes", "detail": "no"} 
//     для строчки знак вопроса в начале подставляется и убирается в зависимости от типа запроса.
// readycontent_func -- обязательный параметр-функция, будет вызвана, когда (и если) придет корректный ответ. 
//     аргумент получит в зависимости от Content-type ответа: 
//     responseXML для text/xml, 
//     responseText для text/plain, 
//     eval(responseText) для application/x-javascript
// errorstate_func -- необязательный параметр-функция, будет вызвана, когда (и если) придет ответ со статусом != 200
// evalfail_func -- необязательный параметр-функция, будет вызвана, если придет ответ со статусом 200, но eval(ajax.responseText) выбросит исключение
// Пример:
// AJAXRequest('POST', {"cmd":"ajaxGetSmth", "easy": "yes" }, function(smth){alert("1st property: "+smth.prop1)});
// TODO как-то разумно отрабатывать неверные параметры
function AJAXRequest(method, param, readycontent_func, errorstate_func, evalfail_func) {
    if (!readycontent_func || typeof(readycontent_func) != "function") {
        return;
    }

    var url = '/registered/main.pl';
    var ajax = new AjaxObject();

    if (errorstate_func && typeof(errorstate_func)=='function')
        ajax.onerrorstate = errorstate_func;
    
    ajax.onreadycontent = function () {
        if(this.contentType.search(/^text\/xml/)!=-1){
            readycontent_func(this.ajax.responseXML);
        } else if(this.contentType.search(/^text\/plain/)!=-1){
            readycontent_func(this.responseText);
        } else if(this.contentType.search(/^application\/x-javascript/)!=-1){
            var res;
            try {
                res = eval('('+this.responseText+')');
            } catch (e) {
                if (evalfail_func && typeof(evalfail_func)=='function')
                    evalfail_func();
                return;
            }
            readycontent_func(res);
        } else {
            if (errorstate_func && typeof(errorstate_func)=='function')
                errorstate_func();
            return;
        }
    }

    // разбираемся с параметрами: из строчки убираем знак вопроса, если есть;
    // если параметры пришли как хеш -- сериализуем в строчку
    var param_str="";
    if(typeof(param) == "string"){
        param_str = param.replace(/^\?/, "");
    } else if(typeof(param) == "object"){
        for(var name in param){
            if (!param.hasOwnProperty(name)) continue;
            if (name != '')
                param_str += "&"+escape(name).replace(/\+/g, '%2B')+"="+escape(param[name]).replace(/\+/g, '%2B');
        }
    }
    
    if (method == 'GET') {
        ajax.open('GET', url+'?'+param_str);
        ajax.send();
    } 
    if (method == 'POST') {
        ajax.open('POST', url);
        ajax.send(param_str); 
    }
}


